package com.lslk.othello.models;

import java.util.HashMap;

import android.content.Context;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.lslk.othello.ActivityOthello;
import com.lslk.othello.R;
import com.lslk.othello.ai.Agent;
import com.lslk.othello.ai.GameBoard;
import com.lslk.othello.helpers.GameFunctions;
import com.lslk.othello.helpers.GameFunctions.Result;
import com.lslk.othello.models.Position.Occupation;
//Corner
//Size
//Side patterns.
//Num Legal Moves.
//Potential Legal Moves.
//Checking for endgame situation.
public class Game{
 private static final String TAG = "Game";
 public Position[] positions;
 public HashMap<String,Position> mapping;
 public int skiped;
 public int numOccupied;
 public boolean isStarted;
 public boolean blackTurn;
 //public boolean aiPlaysBlack; does not store this any more because yea....
 //public boolean aiPlaysWhite;
 public boolean isPaused;
 private LinearLayout msgBoard;
 Toast mToast;
 int[][] history;
 int current_step;
 final Handler mHandler = new Handler();
 public Context activity;
	public Game(ActivityOthello a){
		activity=a;
		setGame(a);
		numOccupied=0;
		mToast=Toast.makeText(activity,"Game started, "+(Preferences.blackPlaysFirst(activity)? "black" : "white")+" moves first", Toast.LENGTH_SHORT);
	}
	public void setGame(ActivityOthello a){
        a.setContentView(R.layout.gameboard);
		LinearLayout board=(LinearLayout) a.findViewById(R.id.board);
		msgBoard=(LinearLayout) a.findViewById(R.id.messages);
		mapping=new HashMap<String,Position>(64);
		positions=new Position[64];
		LinearLayout row;
		Position p;
		for(int i=0;i<8;i++){
			row=new LinearLayout(a);
			for(int j=0;j<8;j++){
				p=new Position(a,(i<<3)+j);
				row.addView(p, j);
				positions[(i<<3)+j]=p;
				mapping.put(""+i+j,p);
			}
			board.addView(row,i);
		}
		positions[27].makeBlack();
		positions[28].makeWhite();
		positions[36].makeBlack();
		positions[35].makeWhite();
		this.isStarted=false;
	}
	public void startGame(){
		this.isStarted=true;
		this.current_step=0;
		this.history=new int[64][64];
		mToast.show();
		this.blackTurn=Preferences.blackPlaysFirst(activity);
		isPaused=false;
		nextTurn();
	}
	public void nextTurn() {
		if(this.assign_legal_moves()==0){
			int result=GameFunctions.isOver(this);
			if(result!=Result.NOT_OVER){
				for(Position p:positions)
					p.legal=false;
				String text="Game over: ";
				switch(result){
					case Result.BLACK_WIN: text+=" Black Win!"; break;
					case Result.WHITE_WIN: text+=" White Win!"; break;
					case Result.TIE: text+=" Tie!"; break;
				}
				mToast.setText(text);
				mToast.show();
				int[] count=GameFunctions.finalCount(this);
				this.addMessage("Final White: "+count[Occupation.WHITE],false);
				this.addMessage("Final Black: "+count[Occupation.BLACK],false);
			}else{
				this.skiped++;
				String msg="Skip: "+((this.blackTurn)? "Black" : "White");
				mToast.setText(msg);
				mToast.show();
				this.addMessage(msg,false);
				this.blackTurn=!this.blackTurn;
				nextTurn();
			} 
		}else{
			this.skiped=0; 
			if((Preferences.aiPlaysBlack(activity) && blackTurn) || ((Preferences.aiPlaysWhite(activity)) && (!blackTurn))){
				//this.makeMove(Agent.getNextMove(getGameBoard(),blackTurn,Preferences.getLimitInMilliseconds(activity)));
				Thread aiThread=new Thread() {
			        public void run() {
			        	block_human=true;
			            ai_move = Agent.getNextMove(getGameBoard(),blackTurn,Preferences.getLimitInMilliseconds(activity),getStepCount());
			            mHandler.post(mUpdateResults);
			            block_human=false;
			        }
				};
				if(!this.isPaused)
					aiThread.start();
				this.aiThread=aiThread;
			}
		}
	}
	public Thread aiThread;
	boolean block_human=false;
	int ai_move;
    final Runnable mUpdateResults = new Runnable() {
        public void run() {
        	makeMove(ai_move);
        }
    };

	public int[] getGameBoard(){
		int[] pieces=new int[64];
		for(int i=0;i<64;i++)
			pieces[i]=positions[i].occupation;
		return pieces;
	}
	public int getStepCount(){
		int sum=0;
		for(Position p:positions)
			sum+=(p.occupation==Occupation.WHITE || p.occupation==Occupation.BLACK)?1:0;
		return sum;
	}
	private int assign_legal_moves() {
		//Log.i(TAG,"Assign Legal Moves for "+((this.blackTurn)?"black":"white"));
		int numLegal=0;
		for(int i=0;i<64;i++){
			Position p=positions[i];
			if(GameFunctions.isLegal(this,i)){
				p.legalize();
				numLegal++;
			}else
				p.legal=false;
		}
		Log.i(TAG,"Found Legal Moves: "+numLegal);
		return numLegal;
	}
	
	public void makeMove(int location){
		if(positions[location].occupation==Occupation.EMPTY)
			if(GameFunctions.isLegal(this, location)){
				if(blackTurn)
					positions[location].makeBlack();
				else
					positions[location].makeWhite();
				this.current_step++;
				GameFunctions.process_move(this,location);
				this.addMessage(String.valueOf(current_step)+". "+((this.blackTurn)?"Black: ":"White: ")+GameBoard.mNames[location]+
							" ("+Agent.last_best_value+", "+Agent.last_time_used+"ms, depth "+Agent.last_depth+")",true);
				
			}else{
				String msg="Illegal move by AI -"+location;
				mToast.setText(msg);
				mToast.show();
				this.addMessage(msg,false);
				return;
			}
		else{
			GameFunctions.process_move(this,location);
			this.current_step++;
			this.addMessage(String.valueOf(current_step)+". "+((this.blackTurn)?"Black: ":"White: ")+GameBoard.mNames[location],true);
		}
		this.blackTurn=!this.blackTurn;
		this.clear_legal_moves();
		this.nextTurn();
	}
	private void clear_legal_moves(){
		for(Position p:positions)
			if(p.occupation==Occupation.EMPTY)
				p.makeEmpty();
	}
	private void addMessage(String msg,boolean addBoard){
		TextView v=new TextView(activity);
		v.setText(msg);
		try{
			if(addBoard){
				final int move=this.current_step;
				this.history[move]=getGameBoard();
				v.setOnClickListener(new OnClickListener(){
					@Override
					public void onClick(View v) {
						loadBoard(move);
						nextTurn();
					}
				});
			}
		}catch(Exception e){}
		msgBoard.addView(v);
	}
	protected void loadBoard(int move) {
		int[] newPos=this.history[move];
		for(int i=0;i<64;i++){
			switch(newPos[i]){
				case Occupation.BLACK: this.positions[i].makeBlack(); break;
				case Occupation.EMPTY: this.positions[i].makeEmpty(); break;
				case Occupation.WHITE: this.positions[i].makeWhite(); break;
			}
		}
	}
	public void assignForOther() {
		this.blackTurn=!this.blackTurn;
		this.clear_legal_moves();
		this.assign_legal_moves();
		this.blackTurn=!this.blackTurn;
	}
	public void evaluate(int turn) {
		mToast.setText("Current State Value as "+((turn==Occupation.BLACK)?"Black":"White")+" is "+Agent.h4(this.getGameBoard(),0,Agent.findLegalMoves(this.getGameBoard(), turn),turn,(turn==2)?1:2));
		mToast.show();
	}
}
